#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<unistd.h>

#define LEFT "["
#define RIGHT "]"
#define LAB "#"
#define MAX_SIZE 1024
#define DEL " \t"
#define ARGC 32
#define EXIT_CODE 1


char target[MAX_SIZE];//拿去命令行中的一整行字符串
char* argv[ARGC];//把字符串分解后放入该数组
int last_normal_code = 0;//退出码
char pwd[MAX_SIZE];

const char* getusrname()
{
	return getenv("USER");
}

const char* gethost()
{
	return getenv("HOME");
}

//const char* getpwd()
//{
//	return getenv("PWD");
//}

void getpwd()
{
	//获取当前工作目录下的绝对路径
	getcwd(pwd,sizeof(pwd));
}


void Init(char* line)
{
	getpwd();
	printf(LEFT"%s@%s %s"RIGHT""LAB" ",getusrname(),gethost(),pwd);
	char* str = fgets(target,MAX_SIZE,stdin);
	assert(str);//输入的指令不能为空，但是一般是不可能的
	(void)str;//要把str使用一下，在release版本下assert就没有了，如果不使用可能会报错
	//"ls -a -l\n\0"
	line[strlen(line)-1] = '\0';
}



int split(char* line)
{
	int i = 0;
	argv[i++] = strtok(line,DEL);
	while(argv[i++] = strtok(NULL,DEL));
	return i - 1;
}

int InbuildExe(int argc,char* _argv[])
{
	if(argc == 2 && strcmp(_argv[0],"cd") == 0)
	{
		chdir(_argv[1]);
		getpwd();
		sprintf(getenv("PWD"),"%s",pwd);
		return 1;
	}
	else if(argc == 2 && strcmp(_argv[0],"export") == 0)
	{
		char* tmp = (char*)malloc(sizeof(char)*strlen(_argv[1]));
		strcpy(tmp,_argv[1]);
		putenv(tmp);
		return 1;
	}
	else if(argc == 2 && strcmp(_argv[0],"echo") == 0)
	{
		if(strcmp(_argv[1],"$?")==0)
		{
			printf("%d\n",last_normal_code);
			last_normal_code = 0;
		}
		else if(*_argv[1] == '$')
		{
			char* val = getenv(_argv[1]+1);
			if(val)
			printf("%s\n",val);
		}
		else
		{
			printf("%s\n",_argv[1]);
		}
		return 1;
	}



	if(strcmp(_argv[0],"ls") == 0)
	{
		_argv[argc++] = "--color";
		_argv[argc] = NULL;
	}
	return 0;
}

//argv是一个数组，里面的元素是char*，然后用char* _argv[]（或者是char** _argv）接收argv的话，是接收的是首元素的地址，
//首元素的地址就有一个*，然后又是char* 类型的有个*，所以就是char** _argv等价于char* argv[]
void NormalExe(char* _argv[])
{
	pid_t id = fork();
	if(id < 0)
	{
		perror("进程创建失败\n");
		return;
	}
	else if(id == 0)
	{
		execvp(_argv[0],_argv);
		exit(EXIT_CODE);
	}
	else 
	{
		int status = 0;
		pid_t ret = waitpid(id,&status,0);
		if(ret == id)
		{
			//printf("等待成功\n");
			last_normal_code = WEXITSTATUS(status);//获取进程的退出码
		}
	}
}

int main()
{
	while(1)
	{
		//初始化
		Init(target);
		
		//分割字符串
		int ret = split(target);
		if(ret == 0) continue;

		//执行内建命令
		int flag = InbuildExe(ret,argv);
		//执行普通命令
		if(!flag) NormalExe(argv);
	}


	return 0;
}
